# -*- coding: utf-8 -*-

import configparser
import logging
import os
import sys
import time

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from backTest_summary import backtest


config = configparser.ConfigParser()
config_file = 'config.ini'
if not os.path.exists(config_file):
    raise FileNotFoundError(f"Configuration file '{config_file}' not found.")


config.read(config_file)
DATA_DIR = config['DEFAULT'].get('DataDir', 'd:/Python/study_data')
LIST_DIR = config['DEFAULT'].get('List', 'list')
LOG_FILE = config['DEFAULT'].get('LogFile_Podifan', 'log_podifan.txt')

if not os.path.exists(DATA_DIR):
    os.makedirs(DATA_DIR)

filelog = True
logger = logging.getLogger('log')
logger.setLevel(logging.DEBUG)
while logger.hasHandlers():
    for i in logger.handlers:
        logger.removeHandler(i)
formatter = logging.Formatter('%(message)s')

if filelog:
    fh = logging.FileHandler(LOG_FILE, encoding='utf-8')
    fh.setLevel(logging.DEBUG)
    fh.setFormatter(formatter)
    logger.addHandler(fh)


def test_stock(path):
    # 获取股票数据
    data = pd.read_csv(path)
    if len(data) > 400:
        data = data[-400:]
    # 确保索引是日期时间类型
    if 'date' in data.columns:
        data.index = pd.to_datetime(data.date)
    else:
        raise ValueError("The 'date' column is missing from the data.")

    # 确保索引是日期时间类型
    data.index = pd.to_datetime(data.date)

    # 计算5日均线
    data['jinQiDiDian'] = data['low'].rolling(window=5).min()
    data['qianQiDiDian'] = data['low'].rolling(window=20).min()
    data['5_day_mavg'] = round(data['close'].rolling(window=5).mean(), 2)
    data['10_day_mavg'] = round(data['close'].rolling(window=10).mean(), 2)
    data['20_day_mavg'] = round(data['close'].rolling(window=20).mean(), 2)
    data['2_day_min_low'] = data['low'].rolling(window=2).min()
    data['3_day_min_low'] = data['low'].rolling(window=3).min()
    data['4_day_min_low'] = data['low'].rolling(window=4).min()
    data['5_day_min_low'] = data['low'].rolling(window=5).min()
    data['6_day_min_low'] = data['low'].rolling(window=6).min()
    data['7_day_min_low'] = data['low'].rolling(window=7).min()
    # data['5_vs_10'] = data['5_day_mavg'] / data['10_day_mavg']
    data['alive'] = data['close'] > data['10_day_mavg']
    data['180_day_min'] = data['close'].rolling(window=180).min()
    data['180_day_max'] = data['close'].rolling(window=180).max()
    data['huicai_10_day_mavg'] = (data['close'] < data['5_day_mavg']) & (data['close'] > 0.9995 * data['10_day_mavg']) & (data['low'] > 0.97 * data['10_day_mavg']) & np.isclose(data['low'], data['10_day_mavg'], atol=0.05 * data['10_day_mavg'])
    data['60_day_max'] = data['close'].rolling(window=60).max()
    data['60_day_min'] = data['close'].rolling(window=60).min()
    data['pingTai'] = data['close'].rolling(window=10).max()
    data['20_day_max'] = data['close'].rolling(window=20).max()
    data['6_day_max'] = data['close'].rolling(window=6).max()
    data['change'] = round(data['close'].pct_change(), 2)
    data['baofali'] = data['change'].rolling(window=6).max()
    data['gravity'] = data['high'] + data['low']
    data['3_day_min'] = data['gravity'].rolling(window=3).min()
    data['6_day_min'] = data['gravity'].rolling(window=6).min()
    data['back'] = (data['high'] < data['high'].shift(1)) & (data['low'] < data['low'].shift(1)) & (data['close'] < data['close'].shift(1))

    # 寻找放量阳线
    data['bullish_volume'] = (data['jinQiDiDian'] > data['qianQiDiDian']) & (data['close'] > data['pingTai'].shift(1)) & (data['close'] * data['outstanding_share'] < 30000000000)
    data['bullish_volume_2nd_day'] = data['bullish_volume'].shift(1) & (data['close'] > data['pingTai'].shift(2)) & (data['close'] > data['5_day_mavg'])
    data['bullish_volume_3rd_day'] = data['bullish_volume_2nd_day'].shift(1) & (data['close'] > data['pingTai'].shift(3)) & (data['close'] > data['5_day_mavg'])

    data['back_test'] = (data['60_day_max'] < 2.5 * data['60_day_min']) & (data['180_day_min'] * 5 > data['180_day_max']) & (
            (data['bullish_volume_3rd_day'].shift(1) & np.isclose(data['low'], data['pingTai'].shift(4), atol=0.06 * data['low']) & (data['close'] > data['pingTai'].shift(4))) |
            (data['bullish_volume_3rd_day'].shift(2) & np.isclose(data['low'], data['pingTai'].shift(5), atol=0.06 * data['low']) & (data['2_day_min_low'] > data['pingTai'].shift(5))) |
            (data['bullish_volume_3rd_day'].shift(3) & np.isclose(data['low'], data['pingTai'].shift(6), atol=0.06 * data['low']) & (data['3_day_min_low'] > data['pingTai'].shift(6))) |
            (data['bullish_volume_3rd_day'].shift(4) & np.isclose(data['low'], data['pingTai'].shift(7), atol=0.06 * data['low']) & (data['4_day_min_low'] > data['pingTai'].shift(7))) |
            (data['bullish_volume_3rd_day'].shift(5) & np.isclose(data['low'], data['pingTai'].shift(8), atol=0.06 * data['low']) & (data['5_day_min_low'] > data['pingTai'].shift(8))) |
            (data['bullish_volume_3rd_day'].shift(6) & np.isclose(data['low'], data['pingTai'].shift(9), atol=0.06 * data['low']) & (data['6_day_min_low'] > data['pingTai'].shift(9))) |
            (data['bullish_volume_3rd_day'].shift(7) & np.isclose(data['low'], data['pingTai'].shift(10), atol=0.06 * data['low']) & (data['7_day_min_low'] > data['pingTai'].shift(10)))
    ) & (data['gravity'] == data['3_day_min']) & (data['low'] > data['20_day_mavg']) & (np.isclose(data['6_day_max'], data['20_day_max'], atol=0.02 * data['6_day_max'])) & (data['baofali'] > 0.05)

    data['buy_signal'] =(data['change'] > -0.03) & (data['high'] < data['low'] * 1.05) & (data['volume'] < data['volume'].shift(1)) & (
        (
            ((data['low'] > 0.995 * data['20_day_mavg']) & np.isclose(data['low'], data['20_day_mavg'], atol=data['20_day_mavg'] * 0.03) & (data['gravity'] == data['6_day_min']) & (data['back_test'].shift(4) | data['back_test'].shift(3) | data['back_test'].shift(2) | data['back_test'].shift(1) | data['back_test']))
          | ((data['low'] > 0.995 * data['10_day_mavg']) & np.isclose(data['low'], data['10_day_mavg'], atol=data['10_day_mavg'] * 0.02) & (data['gravity'] == data['3_day_min']) & (data['back_test'].shift(2) | data['back_test'].shift(1) | data['back_test']))
          | ((data['low'] > 0.995 * data['5_day_mavg']) & np.isclose(data['low'], data['5_day_mavg'], atol=data['5_day_mavg'] * 0.02) & (data['gravity'] == data['3_day_min']) & (data['back_test'].shift(1) | data['back_test']))
        )
    )
                          

    # 检查生成的买入信号日期
    buy_signal_dates = data[data['buy_signal']].index
    dict = {}
    dict[os.path.basename(path).split('.')[0]] = [str(date)[:10] for date in buy_signal_dates]
    # save_name = os.path.basename(path).split('.')[0]
    # data.to_csv(f'd:/Python/study_data/cal/{save_name}.csv')
    return dict


def find_all_buys(path):
    all_buys_code = {}
    all_buys_name = {}
    list_df = pd.read_csv(f'{LIST_DIR}/stocks_daily.csv')
    stocks = dict(zip(list_df['名称'], list_df['代码']))
    for name, code in stocks.items():
        if 'ST' not in name:
            try:
                buys = test_stock(f'{DATA_DIR}/{path}/{code}.csv')
                for key, value in buys.items():
                    for date in value:
                        if date in all_buys_code:
                            all_buys_code[date].append(key)
                            all_buys_name[date].append(name)
                        else:
                            all_buys_code[date] = [key]
                            all_buys_name[date] = [name]
            except FileNotFoundError:
                continue

    all_buys_code_df = pd.DataFrame.from_dict(all_buys_code, orient='index').sort_index()
    all_buys_name_df = pd.DataFrame.from_dict(all_buys_name, orient='index').sort_index()
    all_buys_code_df.to_csv('all_buys_qinglong_tupo_backtest.csv')
    all_buys_name_df.to_csv('all_buys_qinglong_tupo_backtest_name.csv')


if __name__ == '__main__':
    begin_time = time.time()
    # find_all_buys('stocks_test1')
    find_all_buys('stocks')

    end_time = time.time()
    run_time = round(end_time - begin_time)
    hour = run_time // 3600
    minute = (run_time - 3600 * hour) // 60
    second = run_time - 3600 * hour - 60 * minute
    print(f'该程序运行时间：{hour}小时{minute}分钟{second}秒')

    begin_time = time.time()

    test = 'all_buys_qinglong_tupo_backtest.csv'
    backtest(test)

    end_time = time.time()
    run_time = round(end_time - begin_time)
    hour = run_time // 3600
    minute = (run_time - 3600 * hour) // 60
    second = run_time - 3600 * hour - 60 * minute
    print(f'该程序运行时间：{hour}小时{minute}分钟{second}秒')